/*
 * Created on 2007-2-13
 *
 * TODO
 */
package jacky.lanlan.song.extension.spring.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.Ordered;

/**
 * “失败后再执行”拦截器。默认重试次数：<b>2</b>
 * 
 * @author Jacky.Song
 * @see #jacky
 */
@Aspect
public class RetryingAdvisor implements Ordered {

	private static final int DEFAULT_MAX_RETRIES = 2;
	private int order = 1;
	private int maxRetries = DEFAULT_MAX_RETRIES;// 最大重试次数
	
	public int getOrder() {
		return order;
	}
	public void setOrder(int order) {
		this.order = order;
	}
	
	/**
	 * 设置最大重试次数。
	 */
	public void setMaxRetries(int maxRetries) {
		this.maxRetries = maxRetries;
	}
	
	/**
	 * AOP拦截实现操作自动重试。
	 * <p>
	 * 当方法调用失败时，如果认为下一次调用可以成功，那这次调用失败而引发的异常就不应该抛给客户端。
	 * <p>
	 * 这个Advisor可以按照配置的最大重试次数，反复重新调用连接点方法， 直到方法调用成功或达到最大重试次数为止。
	 * 
	 * @param pjp
	 *          连接点处理过程
	 * @return 连接点的返回值
	 * @throws Throwable
	 */
	@Around(
			"@annotation(jacky.lanlan.song.extension.spring.aop.annotation.RetryWhenFail) ||" + // RetryWhenFail标注在方法上或
			"@within(jacky.lanlan.song.extension.spring.aop.annotation.RetryWhenFail) "// 标注在类声明上
			)
	public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
		int numAttempts = 0;
		Exception exception=null;
		// Object [] args=pjp.getArgs();//TODO:args为运行时参数值
		do{
			numAttempts++;
			try {
				return pjp.proceed();
			}
			catch(Exception ex) {
				exception = ex;
			}
		}while(numAttempts <= this.maxRetries);
		throw exception;
	}

}
